<?php
namespace Home\Controller;

use Utuo\DistributionShopForeground;
use Think\Crypt;
use My\Model\DistributionShopOrderModel;
use My\Model\WechatUserModel;
use My\Model\DistributionShopJobTitleModel;
use Utuo\Region;

/**
 * 金牌会员个人中心
 * 一、功能需求
 * 1.
 * 此控制器在微信中禁止浏览，必须使用”在浏览器中打开“，在第三方浏览器中可以正常打开
 * 2. 此控制器下所有页面无法直接在第三方浏览器直接打开，只有从微信中跳转过来的才可以打开
 * 3. 跳转过来后在此控制器下的所有页面可以正常打开
 * 二、实现思路
 * 1. 在微信中产生一个一次性令牌，保存在KVDB或数据库里，同时产生一个访问密钥，附带在地址里。
 * 2. 跳转到第三方浏览器中时用访问密钥和令牌来验证权限，验证成功则保存session，销毁令牌。
 * 3. 根据session来确定是否有访问权限。
 *
 * @author esinger
 */
class DisShopSpaceController extends DistributionShopForeground
{

    const NAME_PREFIX = "DisShopSpace_Token_";

    const CRYPT_KEY = "Dis.Shop.Space";

    const TOKEN_KEY = 'space_token';

    const TOKEN_EXPIRES = 6000;

    protected $isWeixin;

    protected $sessionName;

    protected $tokenName;
    
    /**
     * 跳转前执行
     */
    public function _init()
    {
        // 是否微信浏览器
        $this->isWeixin = strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false;
        $this->assign('isWeixin', $this->isWeixin);
        
        // 设置跳转
        $this->setSupportRedirect($this->isWeixin);
        $this->setCheckLogin($this->isWeixin);
    }

    /**
     * 微信跳转后执行
     */
    public function _after_redirect()
    {
        $timestamp = $_SERVER['REQUEST_TIME'];
        
        if ($this->isWeixin) {
            layout(false);
            if ($this->openId) {
                $accessToken = $this->createAccessToken($this->cid, $this->openId, $timestamp);
                // 保存令牌
                $keyName = $this->getKeyName($this->cid, $this->openId);
                if (! I(self::TOKEN_KEY)) {
                    F($keyName, $accessToken);
                    // 把令牌附加到地址里并跳转
                    redirect($this->getCurrentUrl(array(
                        self::TOKEN_KEY => $accessToken
                    )));
                }
            }
        } else {
            layout('no_nav');
            // 请求令牌是否存在
            $requestToken = I(self::TOKEN_KEY);
            empty($requestToken) && $this->showError('request token not exists(101)');
            
            // 解析请求令牌
            $tokenParams = $this->parseAccessToken($requestToken);
            
            $sid = $tokenParams['sid'];
            $openId = $this->openId = $tokenParams['openId'];
            
            $this->assign('openId', $openId);
            $this->assign('spaceToken', $requestToken);
            
            // 根据sid和openId求出键名
            $keyName = $this->getKeyName($sid, $openId);
            
            // 判断session是否存在且与请求令牌相符
            if (session($keyName) != $requestToken) {
                // session不存在或者与请求令牌不符
                // 先检查请求令牌有效期
                ($tokenParams['timestamp'] + self::TOKEN_EXPIRES < time()) && $this->showError('request token expired(102)');
                
                // 取出验证令牌
                $checkToken = F($keyName);
                empty($checkToken) && $this->showError('check token not exists(103)');
                
                // 比对验证令牌与请求令牌
                if ($checkToken != $requestToken) {
                    $this->showError('token unvalid(104)');
                }
                
                // 令牌相符，清空令牌，保存session
                F($keyName, null);
                session($keyName, $requestToken);
            }
            
            // 获取用户信息
            $this->user = M('WechatUser')->where(array(
                'cid' => $sid,
                'openId' => $openId
            ))->find();
            $this->uid = $this->user['id'];
        }

        $this->user['type'] >= 4 or $this->showError('无权限访问');
    }

    public function indexAction()
    {
        $this->setPageTitle('金牌会员个人中心');
        $this->display('DisShop/space');
    }

    /**
     * 我的下线客户
     */
    public function myCustAction()
    {
        $this->setPageTitle('我的客户');
        $userList = M("WechatUser")->where(array(
            'mid' => $this->user['id'],
            'cid' => $this->cid
        ))
            ->field('*,1 as level')
            ->select();
        $this->assign("userList", $userList);
        layout('no_nav');
        $this->display('DisShop/spaceCust');
    }
    
    /**
     * 下线客户异步请求
     */
    public function downCustAction() {
        $mid = I('fid', $this->uid, 'intval');
        $wechatUserList = M("WechatUser a")->join("__DISTRIBUTION_SHOP_USER_TREE__ b on a.id=b.uid")->where(array('a.mid' => $mid, 'a.cid' => $this->cid))->field('a.*,b.tree')->select();
        foreach ( $wechatUserList as &$v) {
            $v['level'] = $this->getLevel($this->uid, $v['tree']);
        }
        $this->ajaxSuccess('', $wechatUserList);
    }
    
    /**
     * 获得用户级别
     * @param unknown $id 根级id
     * @param unknown $tree tree字符串
     * @return number
     */
    private function getLevel($id, $tree) {
        $i = 0;
        $treeAttr = explode(',', $tree);
        foreach ( $treeAttr as $v ) {
            if ( $v != $id ) {
                $i++;
            } else {
                break;
            }
        }
        return $i;
    }

    /**
     * 我的奖金(积分)
     */
    public function myBonusAction()
    {
        $this->setPageTitle('我的积分');
        $user = $this->getUser();
        $this->assign("user", $user);
        layout('no_nav');
        $this->display('DisShop/spaceBonus');
    }
    

    /**
     * 提现页
     */
    public function withdrawAction() {
        $this->setPageTitle("提现申请");
        $user = $this->getUser();
        $defaultBank = $this->getDefaultBank();
        $user['defaultBank'] = $defaultBank;
        $this->assign("backUrl", urlencode($this->getCurrentUrl()));
        $this->assign("user", $user);
        $this->display('DisShop/spaceWithdraw');
    }
    
    /**
     * 提现提交
     */
    public function withdrawPostAction() {
        function getmicrotime($e = 7) {
            list($u, $s) = explode(' ',microtime());
            return bcadd($u, $s, $e);
        }
        // 默认支付银行
        $defaultUserBankId = I("defaultUserBankId", 0, "intval");
        $distributionShopUserBank = M("DistributionShopUserBank a")->join("__BANK__ b on a.bankId=b.id", "LEFT")->where("a.id=%d", $defaultUserBankId)->field("a.*,b.name as bankName")->find();
        if ( empty($distributionShopUserBank) ) {
            $this->ajaxError('未选择支付的银行');
        }
        // 记录提现
        $no = str_replace('.', '', getmicrotime()).rand(100, 999).$this->uid ;
        $m = M("DistributionShopUserWithdraw");
        if ( $m->create() ) {
            $m->cid = $this->cid;
            $m->uid = $this->uid;
            $m->status = 0;
            $m->createTime = time();
            $m->no = $no;
            $m->bankName = $distributionShopUserBank['bankName'];
            $m->accountName = $distributionShopUserBank['accountName'];
            $m->account = $distributionShopUserBank['account'];
            $user = $this->getUser();
            $minWithdraw = $this->config['min_withdraw'];
            if ( $user['withdrawable']*1 and ($user['withdrawable']*1 >= $m->money*1 ) ) {
                if ( $minWithdraw and $minWithdraw*1 > $m->money*1 ) {  // 判断提现金额是否达到最低提现标准
                    $this->ajaxError('提现金额至少为:'.$minWithdraw);
                }
                if ( $m->add() ) {
                    $this->ajaxSuccess('提现申请成功');
                } else {
                    $this->ajaxError('提现申请失败');
                }
            } else {
                $this->ajaxError('输入的积分超出了可提积分');
            }
        }
        $this->ajaxError($m->getError());
    }
    
    /**
     * 提现记录
     */
    public function withdrawRecordAction() {
        $this->setPageTitle('提现记录');
        $withdrawRecord = M("DistributionShopUserWithdraw")->where("cid=%d and uid=%d", $this->cid, $this->uid)->order('createTime desc')->select();
        $this->assign("withdrawRecord", $withdrawRecord);
        $this->display('DisShop/spaceWithdrawRecord');
    }
    
    /**
     * 获得默认银行
     * @return string
     */
    private function getDefaultBank() {
        $userBank = M("DistributionShopUserBank a")->where(array(
            'a.cid' => $this->cid,
            'a.uid' => $this->uid,
        ))->join("__BANK__ b on a.bankId=b.id", "LEFT")->field("a.*,b.name as bankName")->order('a.isDefault desc')->limit(1)->find();
        $userBank and $userBank['lastCode'] = substr($userBank['account'], -4);
        return $userBank;
    }
    
    /**
     * 添加收款银行
     */
    public function addBankAction() {
        $this->setPageTitle('添加银行卡');
        C("TOKEN_ON", false);
        $bank = array();
        $banks = M("Bank")->getField('id,name');
        $bank['provinceOptions'] = $this->getOption(Region::getProvinceList(), $bank['province'], '==请选择省份==');
        $bank['cityOptions'] = $this->getOption(Region::getCityListByProvince($bank['province']), $bank['city'], '==请选择城市==');
        $bank['bankOptions'] = $this->getOption($banks);
        $this->assign("bank", $bank);
        $this->assign("backUrl", urldecode(htmlspecialchars_decode(I('request.back'))));
        $this->display("DisShop/spaceSaveBank");
    }
    
    /**
     * 保存收款银行
     */
    public function modifyBankAction() {
        $this->setPageTitle("修改银行卡");
        C("TOKEN_ON", false);
        $id = I('id', 0, 'intval');
        $m = M("DistributionShopUserBank");
        $bank = $m->where('id=%d and uid=%d', $id, $this->uid)->find();
        $banks = M("Bank")->getField('id,name');
        $bank['provinceOptions'] = $this->getOption(Region::getProvinceList(), $bank['province'], '==请选择省份==');
        $bank['cityOptions'] = $this->getOption(Region::getCityListByProvince($bank['province']), $bank['city'], '==请选择城市==');
        $bank['bankOptions'] = $this->getOption($banks);
        $this->assign("bank", $bank);
        $this->assign("backUrl", urldecode(htmlspecialchars_decode(I('request.back'))));
        $this->display("DisShop/spaceSaveBank");
    }
    
    /**
     * 银行列表
     */
    public function myBankListAction() {
        $this->setPageTitle('银行卡列表');
        $bankLists = M("DistributionShopUserBank a")->join("__BANK__ b on a.bankId=b.id", "LEFT")->where("a.cid=%d and a.uid=%d", $this->cid, $this->uid)
        ->field("a.*,b.name as bankName")->order('isDefault desc')->select();
        foreach ($bankLists as &$v) {
            $v['lastCode'] = substr($v['account'], -4);
        }
        $this->assign("bankLists", $bankLists);
        $this->assign("backUrl", urlencode(htmlspecialchars_decode(I('request.back'))));
        $this->display("DisShop/spaceBankList");
    }
    
    /**
     * 保存银行
     */
    public function saveBankAction() {
        C("TOKEN_ON", false);
        $m = M("DistributionShopUserBank");
        if ( $m->create() ) {
            $m->cid = $this->cid;
            $m->uid = $this->uid;
            if ( empty($m->id) ) {
                unset($m->id);
                $m->isDefault = 1;
                $id = $m->add();
                if ( $id ) {
                    $m->where(array('id' => array('neq', $id), 'uid' => $this->uid))->setField("isDefault", 0);
                    $this->ajaxSuccess("添加成功");
                } else {
                    $this->ajaxSuccess("添加失败");
                }
            } else {
                if ( false !== $m->where('id=%d', $this->id)->save() ) {
                    $this->ajaxSuccess("修改成功");
                } else {
                    $this->ajaxError("修改失败");
                }
            }
        }
        $this->ajaxError($m->getError());
    }
    

    /**
     * 设置默认银行
     */
    public function setDefaultBankAction() {
        $id = I('bankId', 0, "intval");
        $m = M("DistributionShopUserBank");
        if ( false !== $m->where(array('uid' => $this->uid))->save(array('isDefault' => array('exp', "CASE id WHEN $id THEN 1 ELSE 0 END"))) ) {
            $this->ajaxSuccess('设置成功');
        } else {
            $this->ajaxSuccess('设置失败');
        }
    }
    
    /**
     * 获得用户提现信息
     * @return Ambigous <number, string>
     */
    private function getUser() {
        // 用户信息
        $user = M("WechatUser")->find($this->uid);
        // 可提现
        $money = M("DistributionShopUserWithdraw")->where("uid=%d and status=0", $this->uid)->sum('money'); // 授理中的提现
        $minWithdraw = $this->config['min_withdraw'];
        $withdrawable = $user['bonus']*1 - $user['mention']*1 - $money; // 总收入  - 已提 - 在提 = 可提
        if ( $withdrawable < $minWithdraw ) { // 判断余额是否达到最低提现标准
            $user['withdrawable'] = 0;
        } else {
            $user['withdrawable'] = $withdrawable; // number_format($withdrawable, 2);
        }
        $user["typeName"] = WechatUserModel::getUserTypeName($user['type'], $this->cid, $user['id']);
        $jogTitle = DistributionShopJobTitleModel::getJobTitleList( $this->cid );
        $user['engagedInMoney'] = $money;
        return $user;
    }

    /**
     * 我的分销订单
     */
    public function disOrderAction()
    {
        $this->setPageTitle('订单列表');
        $rewardNames = array(1=>'销售积分',2=>'渠道积分',3=>'反单积分');
        $orderLists = M("DistributionShopOrder a")->join("__WECHAT_USER__ b on a.uid=b.id", "LEFT")
            ->join("__DISTRIBUTION_SHOP_USER_TREE__ c on c.uid=b.id", "LEFT")
            ->field("a.*,b.nickname,c.tree")
            ->where(array(
            'a.cid' => $this->cid,
            'a.order_status' => DistributionShopOrderModel::ORDER_STATUS_COMPLETED,
            '_complex' => array(
                'a.reward_uids' => array(
                    'exp',
                    "!='' and a.reward_uids is not null and find_in_set({$this->uid}, a.reward_uids)"
                ), // 在参与返佣的用户之内
                'a.reward_uids_dealer' => array(
                    'exp',
                    "!='' and a.reward_uids_dealer is not null and find_in_set({$this->uid}, a.reward_uids_dealer)"
                ), // 在参与返佣的用户之内
                '_logic' => 'or'
            )
        ))
            ->select();
        foreach ($orderLists as &$v) {
            $v['all_rewards'] = array_combine(explode(',', $v['reward_uids']), explode(',', $v['reward_bonus']));
            $vDealerBouns = array_combine(explode(',', $v['reward_uids_dealer']), explode(',', $v['reward_bonus_dealer']));
            foreach ($vDealerBouns as $k => $bonus) {
                $v['all_rewards'][$k] += $bonus;
            }
            $v['my_rewards'] = $v['all_rewards'][$this->uid];
            $v['level'] = $this->getLevel($this->uid, $v['tree']);
            $v['reward_name'] = $rewardNames[$v['level']];
        }
        // echo M()->getLastSql();
        $this->assign("orderLists", $orderLists);
        layout('no_nav');
        $this->display('DisShop/spaceOrder');
    }

    /**
     * show error
     * 
     * @param unknown $msg            
     */
    private function showError($msg)
    {
        $msg = sprintf('服务器错误[%s]',$msg);
        if (IS_AJAX){
            $this->ajaxError($msg);
        } else {
            header('Content-type: text/html; charset=utf-8');
            echo '<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />';
            exit($msg);
        }
    }

    /**
     * 创建token
     * 
     * @param unknown $sid            
     * @param unknown $openId            
     * @param unknown $timestamp            
     * @return string
     */
    private function createAccessToken($sid, $openId, $timestamp)
    {
        $data = sprintf("sid=%s&openId=%s&timestamp=%s", $sid, $openId, $timestamp);
        return Crypt::encrypt($data, self::CRYPT_KEY);
    }

    /**
     * 解析token为数组
     * 
     * @param unknown $accessToken            
     * @return string
     */
    private function parseAccessToken($accessToken)
    {
        $accessToken = Crypt::decrypt($accessToken, self::CRYPT_KEY);
        parse_str($accessToken, $accessToken);
        return $accessToken;
    }

    /**
     * 获取键名
     * 
     * @param unknown $sid            
     * @param unknown $openId            
     * @return string
     */
    private function getKeyName($sid, $openId)
    {
        return sprintf('%s_%s_%s', self::NAME_PREFIX, $sid, $openId);
    }
}